package cn.teawooo.tree.node;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import cn.teawooo.log.LocalizationLogger;
import cn.teawooo.log.LoggerFactory;

/**
 * 功能描述：
 * @author teawooo <long1795@gmail.com>
 * @time 2013年8月30日 下午2:08:15
 */
@SuppressWarnings("unchecked")
public abstract class AbstractNode<T> implements Node<T> {
    protected LocalizationLogger logger = LoggerFactory.getLogger(this.getClass());

    protected Node<T> parent;

    protected List<Node<T>> children;

    protected String name;

    protected T data;

    public AbstractNode(String name, T data) {
        this.name = name;
        this.data = data;
    }

    public String toString() {
        return name + "=" + data;
    }

    @Override
    public boolean isLeaf() {
        return children == null || children.isEmpty();
    }

    @Override
    public boolean isRoot() {
        return parent == null;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public T getData() {
        return data;
    }

    @Override
    public <P extends Node<T>> P getParent() {
        return (P) parent;
    }

    @Override
    public <P extends Node<T>> List<P> getParentChain() {
        List<P> list = new ArrayList<P>();
        list.add((P) this);
        if (!isRoot()) {
            list.addAll((Collection<? extends P>) parent.getParentChain());
        }
        return list;
    }

    @Override
    public <C extends Node<T>> List<C> getChildren() {
        return (List<C>) children;
    }

    @Override
    public <C extends Node<T>> C grown(C child) {
        grownImpl(child);
        return (C) this;
    }

    @Override
    public <C extends Node<T>> C grown(List<C> children) {
        for (C child : children) {
            grownImpl(child);
        }
        return (C) this;
    }

    @Override
    public <C extends Node<T>> C grownAndReturnChild(C child) {
        grownImpl(child);
        return child;
    }

    protected <C extends Node<T>> void grownImpl(C child) {
        if (this == child) {
            logger.warn("Circular references!!!");
            return;
        }
        if (children == null) {
            children = new ArrayList<Node<T>>();
        }
        if (children.contains(child)) {
            logger.debug("Node[{}] already has child[{}].", this.name, child.getName());
            return;
        }
        children.add((Node<T>) child);
        child.mount(this);
        logger.debug("Node[{}] added a child[{}].", this.name, child.getName());
        return;
    }

    @Override
    public <P extends Node<T>> P mount(P parent) {
        dependImpl(parent);
        return (P) this;
    }

    @Override
    public <P extends Node<T>> P mountAndReturnParent(P parent) {
        dependImpl(parent);
        return parent;
    }

    protected <P extends Node<T>> void dependImpl(P parent) {
        if (this == parent) {
            logger.warn("Circular references!!!");
            return;
        }

        if (this.parent == null) {
            this.parent = parent;
            parent.grown(this);
            logger.debug("Node[{}] added to parent[{}].", this.name, parent.getName());
        } else {
            logger.debug("Node[{}] already has parent[{}].", this.name, parent.getName());
        }
        return;
    }
}
